#include "eventloop.h"

#include <unistd.h>
#include <sys/eventfd.h>
#include <pthread.h>
#include <signal.h>

#include <utility>

#include "mutex.h"
#include "channel.h"

using namespace tiny_muduo;

namespace{
//下面这个类的作用是屏蔽SIGPIPE信号
/*
 SIGPIPE 是一个在 Unix-like 系统中使用的信号。当进程向一个已经关闭的 socket 或管道（pipe）写入数据时，
 操作系统会发送 SIGPIPE 信号给该进程。默认情况下，当进程收到 SIGPIPE 信号时，它会终止执行。
 因此屏蔽SIGPIPE信号来防止进程意外终止
*/
    class IgnoreSigPipe{
        public:
            IgnoreSigPipe(){
                ::signal(SIGPIPE,SIG_IGN);
            }
    };

    IgnoreSigPipe initObj;
}

EventLoop::EventLoop()
    :tid_(::pthread_self()),
     epoller_(new Epoller()),
     wakeup_fd_(::eventfd(0,EFD_NONBLOCK|EFD_CLOEXEC)),
     wakeup_channel_(new Channel(this,wakeup_fd_)),
     calling_functors_(false){
    wakeup_channel_->SetReadCallback(std::bind(&EventLoop::HandleRead,this));
    wakeup_channel_->EnableReading();
}

EventLoop::~EventLoop(){
    wakeup_channel_->DisableAll();
    Remove(wakeup_channel_.get());
    close(wakeup_fd_);
}

void EventLoop::Loop(){
    assert(IsInThreadLoop());
    while(1){
        active_channels_.clear();
        epoller_->Poll(active_channels_);
        for(const auto& channel : active_channels_){
            channel->HandleEvent();
        }
        DoToDoList();
    }
}

void EventLoop::HandleRead(){
    uint64_t read_one_byte=1;
    ::read(wakeup_fd_,&read_one_byte,sizeof(read_one_byte));
    return;
}

void EventLoop::QueueOneFunc(BasicFunc func){
    {
        MutexLockGuard lock(mutex_);
        to_do_list_.emplace_back(std::move(func));
    }
    if(!IsInThreadLoop()||calling_functors_){
        uint64_t write_one_byte=1;
        ::write(wakeup_fd_,&write_one_byte,sizeof(write_one_byte));
    }
}


void EventLoop::RunOneFunc(BasicFunc func){
    if(IsInThreadLoop()){
        func();
    }else{
        QueueOneFunc(std::move(func));
    }
}

void EventLoop::DoToDoList(){
    ToDoList functors;
    calling_functors_=true;
    {
        MutexLockGuard lock(mutex_);
        functors.swap(to_do_list_); //意思就是把to_do_list赋值给functors，不过使用交换的方式
    }

    for(const auto& func:functors){
        func();
    }
    calling_functors_=false;
}
